!
!     Demonstrates use of MatDuplicate() for a shell matrix with a context
!
     MODULE solver_context_ex20f
#include "petsc/finclude/petscmat.h"
       USE petscmat
       IMPLICIT NONE
       TYPE :: MatCtx
         PetscReal :: lambda
       END TYPE MatCtx
     END MODULE solver_context_ex20f

     MODULE solver_context_interfaces_ex20f
       USE solver_context_ex20f
       IMPLICIT NONE

       INTERFACE MatCreateShell
         SUBROUTINE MatCreateShell(comm,mloc,nloc,m,n,ctx,mat,ierr)
           USE solver_context_ex20f
           MPI_Comm :: comm
           PetscInt :: mloc,nloc,m,n
           TYPE(MatCtx) :: ctx
           Mat :: mat
           PetscErrorCode :: ierr
         END SUBROUTINE MatCreateShell
       END INTERFACE MatCreateShell

       INTERFACE MatShellSetContext
         SUBROUTINE MatShellSetContext(mat,ctx,ierr)
           USE solver_context_ex20f
           Mat :: mat
           TYPE(MatCtx) :: ctx
           PetscErrorCode :: ierr
         END SUBROUTINE MatShellSetContext
       END INTERFACE MatShellSetContext

       INTERFACE MatShellGetContext
         SUBROUTINE MatShellGetContext(mat,ctx,ierr)
           USE solver_context_ex20f
           Mat :: mat
           TYPE(MatCtx), POINTER :: ctx
           PetscErrorCode :: ierr
         END SUBROUTINE MatShellGetContext
       END INTERFACE MatShellGetContext

     END MODULE solver_context_interfaces_ex20f

! ----------------------------------------------------
!                    main program
! ----------------------------------------------------
     PROGRAM main
#include "petsc/finclude/petscmat.h"
       USE solver_context_interfaces_ex20f
       IMPLICIT NONE
       Mat                  :: F, Fcopy
       TYPE(MatCtx)         :: ctxF
       TYPE(MatCtx),POINTER :: ctxF_pt, ctxFcopy_pt
       PetscErrorCode       :: ierr
       PetscInt             :: n=128
       external MatDuplicate_F

       PetscCallA(PetscInitialize(ierr))
       ctxF%lambda = 3.14d0
       PetscCallA(MatCreateShell(PETSC_COMM_WORLD,PETSC_DECIDE,PETSC_DECIDE,n,n,ctxF,F,ierr))
       PetscCallA(MatShellSetOperation(F,MATOP_DUPLICATE,MatDuplicate_F,ierr))
       PRINT*,'ctxF%lambda = ',ctxF%lambda

       PetscCallA(MatShellGetContext(F,ctxF_pt,ierr))
       PRINT*,'ctxF_pt%lambda = ',ctxF_pt%lambda

       PetscCallA(MatDuplicate(F,MAT_DO_NOT_COPY_VALUES,Fcopy,ierr))
       PetscCallA(MatShellGetContext(Fcopy,ctxFcopy_pt,ierr))
       PRINT*,'ctxFcopy_pt%lambda = ',ctxFcopy_pt%lambda

       PetscCallA(MatDestroy(F,ierr))
       PetscCallA(MatDestroy(Fcopy,ierr))
       PetscCallA(PetscFinalize(ierr))
     END PROGRAM main

       SUBROUTINE MatDuplicate_F(F, opt, M, ierr)
       USE solver_context_interfaces_ex20f
       IMPLICIT NONE

         Mat                  :: F, M
         MatDuplicateOption   :: opt
         PetscErrorCode       :: ierr
         PetscInt             :: ml,nl
         TYPE(MatCtx),POINTER :: ctxM,ctxF_pt
         external MatDestroy_F

         PetscCall(MatGetLocalSize(F,ml,nl,ierr))
         PetscCall(MatShellGetContext(F,ctxF_pt,ierr))
         allocate(ctxM)
         ctxM%lambda = ctxF_pt%lambda
         PetscCall(MatCreateShell(PETSC_COMM_WORLD,ml,nl,PETSC_DETERMINE,PETSC_DETERMINE,ctxM,M,ierr))
!        PetscCall(MatShellSetOperation(M,MATOP_DUPLICATE,MatDuplicate_F,ierr))
         PetscCall(MatShellSetOperation(M,MATOP_DESTROY,MatDestroy_F,ierr))
       END SUBROUTINE MatDuplicate_F

       SUBROUTINE MatDestroy_F(F, ierr)
       USE solver_context_interfaces_ex20f
       IMPLICIT NONE

         Mat                  :: F
         PetscErrorCode       :: ierr
         TYPE(MatCtx),POINTER :: ctxF_pt
         PetscCall(MatShellGetContext(F,ctxF_pt,ierr))
         deallocate(ctxF_pt)
       END SUBROUTINE MatDestroy_F

!/*TEST
!
!     build:
!       requires: double
!
!     test:
!
!TEST*/
